最後幾天,我想要優化首頁的功能,讓它顯示當前月份即將到期的物品。所以我們需要在首頁上方的導覽列中,加入年份和月份的選擇功能。今天,我們將實作首頁上方的月份顯示功能,並且在點擊月份按鈕後,彈出自定義視窗,讓使用者能選擇特定的年份和月份。此功能將使使用者能夠快速切換至不同月份,接下來我們會繼續實作這個月份選擇器的具體邏輯。
YearMonthPicker 是自定義的月份選擇器,使用者可以通過此選擇器快速切換年份和月份。
首先,建立一個 YearMonthPicker 結構,通過 @Binding 來管理所選日期和彈窗的顯示狀態。使用 Calendar.current.shortMonthSymbols 提供月份的顯示,並用 LazyVGrid
和 GridItem
將月份顯示成網格排列。
struct YearMonthPicker: View {
@Binding var selectedDate: Date
@Binding var isShowing: Bool
let months: [String] = Calendar.current.shortMonthSymbols
let columns = [GridItem(.adaptive(minimum: 80))]
使用 ZStack
來包裝背景及彈窗內容。當彈窗顯示時,點擊背景的空白區域可以關閉彈窗。
ZStack {
if isShowing {
Rectangle()
.background(Color(.systemBackground))
.opacity(0.3)
.ignoresSafeArea()
.onTapGesture {
isShowing.toggle()
}
用 HStack
顯示年份,並在左右兩側加上 chevron.left 和 chevron.right 圖示,讓使用者點擊來切換年份。
HStack {
Image(systemName: "chevron.left")
.frame(width: 24.0)
.onTapGesture {
var dateComponent = DateComponents()
dateComponent.year = -1
selectedDate = Calendar.current.date(byAdding: dateComponent, to: selectedDate)!
}
Spacer()
Text(selectedDate, formatter: formatter(type: "year"))
.fontWeight(.bold)
Spacer()
Image(systemName: "chevron.right")
.frame(width: 24.0)
.onTapGesture {
var dateComponent = DateComponents()
dateComponent.year = 1
selectedDate = Calendar.current.date(byAdding: dateComponent, to: selectedDate)!
}
}
使用 LazyVGrid
將月份排列為網格顯示。當用戶點擊某個月份時,更新 selectedDate,並讓選中的月份背景顯示不同顏色。
LazyVGrid(columns: columns, spacing: 20) {
ForEach(months, id: \.self) { item in
Text(item)
.font(.headline)
.frame(width: 60, height: 33)
.background(item == formatter(type: "month").string(from: selectedDate) ? Color("AccentColor") : Color("BgColor"))
.cornerRadius(8)
.onTapGesture {
var dateComponent = DateComponents(year: Int(formatter(type: "year").string(from: selectedDate)), month: months.firstIndex(of: item)! + 1, day: 1)
selectedDate = Calendar.current.date(from: dateComponent)!
}
}
}
使用 DateFormatter
格式化顯示年份或月份,根據不同的參數來調整輸出的格式。
func formatter(type: String) -> DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = type == "year" ? "yyyy" : "MMM"
return formatter
}
最後,在 HomeView 中使用 YearMonthPicker,並用 @State
管理 selectedDate 和彈窗顯示的狀態。點擊上方的月份按鈕,顯示彈窗進行年月選擇。
@State private var isShowDatePicker = false
var body: some View {
// 略...
YearMonthPicker(selectedDate: $viewModel.selectedDate, isShowing: $isShowDatePicker)
// 略...
.toolbar {
ToolbarItem(placement: .principal) {
Button(action: {
self.isShowDatePicker.toggle()
}) {
Text(dateFormatter.string(from: viewModel.selectedDate))
.font(.headline)
.foregroundColor(Color("FontColor"))
}
}
// 略...
}
private var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.locale = Locale.current
if formatter.locale.identifier.contains("zh") {
formatter.dateFormat = "yyyy年 MMM"
} else {
formatter.dateFormat = "yyyy MMM"
}
return formatter
}
今天實作導覽列月份顯示功能,並且為此新增了一個自定義的月份選擇器。透過 YearMonthPicker,使用者可以輕鬆地切換年份和月份,並在首頁上更新選擇的月份。明天我們將在首頁新增提示到期物品的區塊,明天見囉~
參考資料:Create custom month & year date picker in SwiftUI • Location Tracking Apps for iOS & Android